#include "CharacterData.h"
#include "CharacterRecord.h"
#include "DndData.h"
#include "Race.h"
#include "ClassDetails.h"

#include <Xml/Xml.h>

#include <QDebug>
#include <QVariant>

static const char *abils[] = {
    "strength",
    "constitution",
    "dexterity",
    "intelligence",
    "wisdom",
    "charisma"
};

CharacterData::CharacterData(const QString &title)
    : TitledData(title)
    , mExtClassName("Unspecified Class")
    , mExtRaceName("Unspecified Race")
    , mDetails("Unspecified Details")
{
    for (int i = 0; i < DndData::NUM_ABILITIES; ++i)
        this->mAbilities[i] = 0;
}

CharacterData::CharacterData(const CharacterData &rhs)
    : TitledData(rhs.title())
{
    for (int i = 0; i < DndData::NUM_ABILITIES; ++i)
        this->mAbilities[i] = rhs.mAbilities[i];
    this->mClassName = rhs.mClassName;
    this->mRace = rhs.mRace;
    mPowers = rhs.mPowers;
    mTraits = rhs.mTraits;
    mFeats = rhs.mFeats;
}

CharacterData::~CharacterData()
{
}

QString CharacterData::className() const
{
    QString className = mExtClassName;
    if (className.isEmpty())
        className = DndData::CLASS_NAMES[mClassName];
    return className;
}

void CharacterData::setClassName(const QString &cn)
{
    if (cn.isEmpty())
    {
        qDebug() << "Refusing to set className to empty string";
        return;
    }
    int i;
    mExtClassName.clear();
    for (i = 0; i < DndData::NUM_CLASSES; ++i)
        if (cn == DndData::CLASS_NAMES[i])
            break;
    if (i == DndData::NUM_CLASSES)
        mExtClassName = cn;
    else
        mClassName = static_cast<DndData::ClassName>(i);
}

QString CharacterData::race() const
{
    QString raceName = mExtRaceName;
    if (raceName.isEmpty())
        raceName = DndData::RACE_NAMES[mRace];
    return raceName;
}

void CharacterData::setRace(const QString &rn)
{
    if (rn.isEmpty())
    {
        qDebug() << "Refusing to set race to empty string";
        return;
    }
    int i;
    mExtRaceName.clear();
    for (i = 0; i < DndData::NUM_RACES; ++i)
        if (rn == DndData::RACE_NAMES[i])
            break;
    if (i == DndData::NUM_RACES)
        mExtRaceName = rn;
    else
        mRace = static_cast<DndData::RaceName>(i);
}

void CharacterData::saveToXml() const
{
    Xml xml(XmlPath(XmlPath::CHARACTER_BASE, XmlPath::safeDataPathName(title())));
    appendTag(xml, "Title", title());
    appendTag(xml, "ClassName", className());
    appendTag(xml, "Race", race());
    for (int i = 0; i < DndData::NUM_ABILITIES; ++i)
        appendTag(xml, DndData::ABILITY_NAMES[i], mAbilities[i]);
    appendTitleArray(xml, "Powers", mPowers);
    appendTitleArray(xml, "Traits", mTraits);
    appendTitleArray(xml, "Feats", mFeats);
    xml.serializeXml();
}

void CharacterData::loadFromXml()
{
    Xml xml(XmlPath(XmlPath::CHARACTER_BASE, XmlPath::safeDataPathName(title())));
    xml.deserializeXml();
    setTitle(xml.value("Title"));
    qDebug() << "setting title to" << xml.value("Title");
    setClassName(value<QString>(xml, "ClassName"));
    setRace(value<QString>(xml, "Race"));
    for (int i = 0; i < DndData::NUM_ABILITIES; ++i) {
        mAbilities[i] = value<int>(xml, DndData::ABILITY_NAMES[i]);
        qDebug() << "ability" << DndData::ABILITY_NAMES[i] << "set to" << mAbilities[i];
    }
    mPowers = valueTitleArray<Power>(xml, "Powers");
    mTraits = valueTitleArray<Trait>(xml, "Traits");
    mFeats = valueTitleArray<Feat>(xml, "Feats");
}

void CharacterData::fill(CharacterRecord *record)
{
    record->setName(title());
    for (int i = 0; i < DndData::NUM_ABILITIES; ++i)
        record->setProperty(abils[i], QVariant(mAbilities[i]));
    record->setClassName(className());
    record->setRace(race());
    Race raceDetails(race());

}

QString CharacterData::description() const
{
    return QString("%1 %2").arg(DndData::RACE_NAMES[mRace]).arg(DndData::CLASS_NAMES[mClassName]);
}

CharacterData &CharacterData::operator=(const CharacterData &rhs)
{
    for (int i = 0; i < DndData::NUM_ABILITIES; ++i)
        this->mAbilities[i] = rhs.mAbilities[i];
    this->mClassName = rhs.mClassName;
    this->mRace = rhs.mRace;
    mPowers = rhs.mPowers;
    mTraits = rhs.mTraits;
    mFeats = rhs.mFeats;
    return *this;
}
